package com.bruce.ai.alibaba.agentcard.discovery.retry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 重试执行器
 * 提供同步和异步的重试执行功能
 */
public class RetryExecutor {
    
    private static final Logger logger = LoggerFactory.getLogger(RetryExecutor.class);
    
    private final RetryStrategy strategy;
    private final Executor executor;
    
    public RetryExecutor(RetryStrategy strategy) {
        this(strategy, ForkJoinPool.commonPool());
    }
    
    public RetryExecutor(RetryStrategy strategy, Executor executor) {
        this.strategy = strategy;
        this.executor = executor;
    }
    
    /**
     * 同步执行带重试的操作
     * @param operation 要执行的操作
     * @param <T> 返回类型
     * @return 操作结果
     * @throws Exception 如果所有重试都失败
     */
    public <T> T execute(Callable<T> operation) throws Exception {
        return execute(operation, null);
    }
    
    /**
     * 同步执行带重试的操作，支持失败回调
     * @param operation 要执行的操作
     * @param onRetry 重试时的回调函数
     * @param <T> 返回类型
     * @return 操作结果
     * @throws Exception 如果所有重试都失败
     */
    public <T> T execute(Callable<T> operation, RetryCallback onRetry) throws Exception {
        Exception lastException = null;
        int attempt = 0;
        
        while (attempt < strategy.getMaxRetries()) {
            attempt++;
            
            try {
                logger.debug("Executing operation, attempt {}/{}", attempt, strategy.getMaxRetries());
                T result = operation.call();
                
                if (attempt > 1) {
                    logger.info("Operation succeeded on attempt {}/{}", attempt, strategy.getMaxRetries());
                }
                
                return result;
                
            } catch (Exception e) {
                lastException = e;
                
                logger.warn("Operation failed on attempt {}/{}: {}", 
                           attempt, strategy.getMaxRetries(), e.getMessage());
                
                // 检查是否应该重试
                if (!strategy.shouldRetry(e, attempt)) {
                    logger.debug("Not retrying due to strategy condition");
                    break;
                }
                
                // 如果还有重试机会，等待后重试
                if (attempt < strategy.getMaxRetries()) {
                    long delay = strategy.calculateDelay(attempt);
                    
                    if (onRetry != null) {
                        onRetry.onRetry(attempt, e, delay);
                    }
                    
                    logger.debug("Waiting {}ms before retry {}", delay, attempt + 1);
                    
                    try {
                        Thread.sleep(delay);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("Operation interrupted during retry", ie);
                    }
                }
            }
        }
        
        // 所有重试都失败了
        logger.error("All {} retry attempts failed", strategy.getMaxRetries());
        throw new RetryExhaustedException("All retry attempts failed", lastException, attempt);
    }
    
    /**
     * 异步执行带重试的操作
     * @param operation 要执行的操作
     * @param <T> 返回类型
     * @return CompletableFuture包装的结果
     */
    public <T> CompletableFuture<T> executeAsync(Supplier<T> operation) {
        return executeAsync(operation, null);
    }
    
    /**
     * 异步执行带重试的操作，支持失败回调
     * @param operation 要执行的操作
     * @param onRetry 重试时的回调函数
     * @param <T> 返回类型
     * @return CompletableFuture包装的结果
     */
    public <T> CompletableFuture<T> executeAsync(Supplier<T> operation, RetryCallback onRetry) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return execute(() -> operation.get(), onRetry);
            } catch (Exception e) {
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                } else {
                    throw new RuntimeException(e);
                }
            }
        }, executor);
    }
    
    /**
     * 异步执行带重试的操作（Callable版本）
     * @param operation 要执行的操作
     * @param <T> 返回类型
     * @return CompletableFuture包装的结果
     */
    public <T> CompletableFuture<T> executeAsync(Callable<T> operation) {
        return executeAsync(operation, null);
    }
    
    /**
     * 异步执行带重试的操作（Callable版本），支持失败回调
     * @param operation 要执行的操作
     * @param onRetry 重试时的回调函数
     * @param <T> 返回类型
     * @return CompletableFuture包装的结果
     */
    public <T> CompletableFuture<T> executeAsync(Callable<T> operation, RetryCallback onRetry) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return execute(operation, onRetry);
            } catch (Exception e) {
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                } else {
                    throw new RuntimeException(e);
                }
            }
        }, executor);
    }
    
    /**
     * 执行带重试的操作，并在失败时应用回退策略
     * @param operation 主要操作
     * @param fallback 回退操作
     * @param <T> 返回类型
     * @return 操作结果
     */
    public <T> T executeWithFallback(Callable<T> operation, Function<Exception, T> fallback) {
        try {
            return execute(operation);
        } catch (Exception e) {
            logger.warn("All retries failed, applying fallback strategy", e);
            return fallback.apply(e);
        }
    }
    
    /**
     * 异步执行带重试的操作，并在失败时应用回退策略
     * @param operation 主要操作
     * @param fallback 回退操作
     * @param <T> 返回类型
     * @return CompletableFuture包装的结果
     */
    public <T> CompletableFuture<T> executeAsyncWithFallback(Supplier<T> operation, 
                                                            Function<Exception, T> fallback) {
        return executeAsync(operation)
                .exceptionally(throwable -> {
                    logger.warn("Async operation with retries failed, applying fallback", throwable);
                    return fallback.apply((Exception) throwable.getCause());
                });
    }
    
    /**
     * 重试回调接口
     */
    @FunctionalInterface
    public interface RetryCallback {
        /**
         * 重试时调用
         * @param attempt 当前重试次数
         * @param exception 导致重试的异常
         * @param delayMs 下次重试前的延迟时间
         */
        void onRetry(int attempt, Exception exception, long delayMs);
    }
    
    /**
     * 重试耗尽异常
     */
    public static class RetryExhaustedException extends Exception {
        private final int attempts;
        
        public RetryExhaustedException(String message, Throwable cause, int attempts) {
            super(message, cause);
            this.attempts = attempts;
        }
        
        public int getAttempts() {
            return attempts;
        }
    }
    
    /**
     * 获取重试策略
     */
    public RetryStrategy getStrategy() {
        return strategy;
    }
    
    /**
     * 创建默认重试执行器
     */
    public static RetryExecutor defaultExecutor() {
        return new RetryExecutor(RetryStrategy.defaultStrategy());
    }
    
    /**
     * 创建快速重试执行器
     */
    public static RetryExecutor fastExecutor() {
        return new RetryExecutor(RetryStrategy.fastRetry());
    }
    
    /**
     * 创建慢重试执行器
     */
    public static RetryExecutor slowExecutor() {
        return new RetryExecutor(RetryStrategy.slowRetry());
    }
}